package com.google.guava.io;

import com.google.common.base.Preconditions;

/**
 * base64 加密,解密
 *
 * @author fuc
 * @create 2020-09-27
 */
public final class Base64<main> {

  private static final String CODE_STRING =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

  private static final char[] CODE_DICT = CODE_STRING.toCharArray();

  private Base64() {}

  public static String encode(String plain) {
    Preconditions.checkNotNull(plain);
    StringBuilder result = new StringBuilder();
    String binaryString = toBinary(plain);
    // should append
    int delta = 6 - binaryString.length() % 6;
    for (int i = 0; i < delta && delta != 6; i++) {
      binaryString += "0";
    }

    for (int index = 0; index < binaryString.length() / 6; index++) {
      int begin = index * 6;
      String encodeString = binaryString.substring(begin, begin + 6);
      char encodeChar = CODE_DICT[Integer.valueOf(encodeString, 2)];
      result.append(encodeChar);
    }

    if (delta != 6) {
      for (int i = 0; i < delta / 2; i++) {
        result.append("=");
      }
    }
    return result.toString();
  }

  private static String toBinary(final String source) {
    final StringBuilder binaryResult = new StringBuilder();

    for (int index = 0; index < source.length(); index++) {
      String charBin = Integer.toBinaryString(source.charAt(index));
      int delta = 8 - charBin.length();
      for (int i = 0; i < delta; i++) {
        charBin = "0" + charBin;
      }
      binaryResult.append(charBin);
    }
    return binaryResult.toString();
  }

  public static String decode(final String encrypt) {
    StringBuilder builder = new StringBuilder();
    String temp = encrypt;
    int equalIndex = temp.indexOf("=");
    if (equalIndex > 0) {
      temp = temp.substring(0, equalIndex);
    }
    String base64Binary = toBase64Binary(temp);
    for (int i = 0; i < base64Binary.length() / 8; i++) {
      int begin = i * 8;
      String str = base64Binary.substring(begin, begin + 8);
      builder.append(Character.toChars(Integer.valueOf(str, 2)));
    }
    return builder.toString();
  }

  private static String toBase64Binary(final String source) {
    final StringBuilder binaryResult = new StringBuilder();
    for (int index = 0; index < source.length(); index++) {
      int i = CODE_STRING.indexOf(source.charAt(index));
      String charBin = Integer.toBinaryString(i);
      int delta = 6 - charBin.length();
      for (int i1 = 0; i1 < delta; i1++) {
        charBin = "0" + charBin;
      }
      binaryResult.append(charBin);
    }
    return binaryResult.toString();
  }

  public static void main(String[] args) {
    final String encode = encode("hello world");
    System.out.println(encode);
    String decode = decode(encode);
    System.out.println(decode);
  }
}
